package com.xuln.framework.dao;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.xuln.common.util.BaseDaoUtil;
import com.xuln.common.util.GenericsUtils;
import com.xuln.common.util.PaginationSupport;
import com.xuln.framework.entity.EntityKeySequences;

public class BaseDao<T, PK extends Serializable> extends HibernateDaoSupport implements IBaseDao<T, PK> {
	protected Logger log = LoggerFactory.getLogger(this.getClass());

	@SuppressWarnings("unchecked")
	protected Class<T> entityClass = GenericsUtils.getSuperClassGenricType(this.getClass());

	/**
	 * 清除缓存，未作测试通过
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 3, 2010 void
	 */
	public void clear() {
		getHibernateTemplate().clear();
	}

	/**
	 * 通过ID判断实体是否存在
	 * 
	 * @param id
	 *            实体ID
	 * @return - true if it exists, false if it doesn't
	 */
	@SuppressWarnings("unchecked")
	public boolean exists(PK id) {
		T entity = (T) getHibernateTemplate().get(entityClass, id);
		return entity != null;
	}

	/**
	 * 加载所有的实体
	 */
	@SuppressWarnings("unchecked")
	public List<T> loadAll() {
		return (List<T>) getHibernateTemplate().loadAll(entityClass);
	}

	/**
	 * 加载实体
	 */
	@SuppressWarnings("unchecked")
	public T load(PK id) {
		return (T) getHibernateTemplate().load(entityClass, id);
	}

	/**
	 * 根据ID查找实体
	 */
	@SuppressWarnings("unchecked")
	public T get(PK id) {
		return (T) getHibernateTemplate().get(entityClass, id);
	}

	/**
	 * 根据hql和可变参数数组查询
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 3, 2010
	 * @param hql
	 * @param values
	 *            可变参数数组
	 * @return List<T>
	 */
	@SuppressWarnings("unchecked")
	public List<T> find(String hql, Object... values) {
		return (List<T>) getHibernateTemplate().find(hql, values);
	}

	/**
	 * 根据hql和可变参数数组查询，返回第一条记录
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 3, 2010
	 * @param hql
	 * @param values
	 *            可变参数数组
	 * @return List<T>
	 */
	@SuppressWarnings("unchecked")
	public T findTop1Entity(String hql, Object... values) {
		List<T> list = (List<T>) getHibernateTemplate().find(hql, values);
		if (list.size() > 0)
			return list.get(0);
		return null;
	}

	/**
	 * 根据给定的实例查找实体<br>
	 * 此方法测试未通过 ：试验查找结果是找出了写实体name属性相同的实体<br>
	 * 生成语句如下：select * from MyEntity where name=?
	 */
	@SuppressWarnings("unchecked")
	@Deprecated
	public List<T> findByExample(T entity) {
		List<T> results = (List<T>) getHibernateTemplate().findByExample(entity);
		return results;
	}

	/**
	 * 根据ID查找实体
	 */
	public T findById(PK id) {
		return this.get(id);
	}

	/**
	 * 根据hql查询,map存储参数 <br>
	 * String hql = "from MyEntity where name=:paramName";
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 3, 2010
	 * @param hql
	 * @param map
	 *            <String, Object>
	 * @return List<T>
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByMap(String hql, Map<String, Object> map) {
		if (map == null)
			map = new HashMap();
		Set<String> keys = map.keySet();
		String[] paramNames = new String[keys.size()];
		keys.toArray(paramNames);
		Object[] values = map.values().toArray();
		return (List<T>) getHibernateTemplate().findByNamedParam(hql, paramNames, values);
	}

	/**
	 * 根据某个具体属性进行查找
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByProperty(String propertyName, Object value) {
		String queryString = "from " + entityClass.getName() + " as model where model." + propertyName + "= ?";
		return (List<T>) getHibernateTemplate().find(queryString, value);
	}

	/**
	 * 执行采用本地SQL<br>
	 * 当参数为map,且map元素的value为Class时，查看结果返回实体对象
	 * 
	 * @param sql
	 * @param values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List findByQuerySQL(String sql, Object... values) {
		Query query = createSQLQuery(sql, values);
		return query.list();
	}

	/**
	 * 执行前一刻，先去数据库根据PK查找数据库中是否存在该记录，如果存在则合并，不存在则保存
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 7, 2010
	 * @param entity
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T merge(T entity) {
		return (T) getHibernateTemplate().merge(entity);
	}

	/**
	 * 保存实体
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 3, 2010
	 * @param entity
	 * @return PK
	 */
	@SuppressWarnings("unchecked")
	public PK save(T entity) {
		return (PK) getHibernateTemplate().save(entity);
	}

	/**
	 * 保存或更新实体 <br>
	 * 执行前一刻，不从数据库查找
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 3, 2010
	 * @param entity
	 *            void
	 */
	@SuppressWarnings("unchecked")
	public void saveOrUpdate(T entity) {
		getHibernateTemplate().saveOrUpdate(entity);
	}

	/**
	 * 保存或更新实体集合
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 3, 2010
	 * @param entities
	 *            void
	 */
	@SuppressWarnings("unchecked")
	public void saveOrUpdateAll(List<T> entities) {
		getHibernateTemplate().saveOrUpdateAll(entities);
	}

	/**
	 * 更新已存在的实体
	 */
	public void update(T entity) {
		getHibernateTemplate().update(entity);
	}

	/**
	 * 删除指定ID的实体
	 */
	public void deleteById(PK id) {
		T entity = findById(id);
		if (entity != null)
			getHibernateTemplate().delete(entity);
	}

	/**
	 * 删除指定实体
	 */
	public void delete(T entity) {
		getHibernateTemplate().delete(entity);
	}

	/**
	 * 删除指定实体集合
	 */
	public void deleteAll(List<T> entities) {
		getHibernateTemplate().deleteAll(entities);
	}

	/**
	 * 执行更新hql语句
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 7, 2010
	 * @param hql
	 * @param values
	 * @return int
	 */
	public int executeUpdate(String hql, Object... values) {

		Query query = getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.executeUpdate();
	}

	/**
	 * 根据hql加载分页，默认页大小，从第0条开始
	 */
	public PaginationSupport findPageByQuery(String hql, Object... values) {
		return findPageByQuery(hql, 0, PaginationSupport.PAGESIZE, values);
	}

	/**
	 * 根据hql加载分页，默认页大小，从第startIndex条开始
	 */
	public PaginationSupport findPageByQuery(String hql, int startIndex, Object... values) {
		return findPageByQuery(hql, startIndex, PaginationSupport.PAGESIZE, values);
	}

	/**
	 * 根据hql加载分页，指定页大小和起始位置
	 */
	@SuppressWarnings("unchecked")
	public PaginationSupport findPageByQuery(String hql, int startIndex, int pageSize, Object... values) {
		int totalCount = getCountByQuery(hql, values);

		if (totalCount < 1) {
			return new PaginationSupport(new ArrayList(0), 0);
		}

		Query query = createQuery(hql, values);
		List items = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
		PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);
		return ps;
	}

	/**
	 * 根据hql统计总数
	 */
	@SuppressWarnings("unchecked")
	public int getCountByQuery(String hql, Object... values) {
		List countlist = null;
		String countQueryString = " select count (*) " + BaseDaoUtil.removeSelect(BaseDaoUtil.removeOrders(hql));
		try {
			countlist = getHibernateTemplate().find(countQueryString, values);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ((Long) countlist.get(0)).intValue();
	}

	/**
	 * 调用方式如下： <br>
	 * dao.createQuery(hql)<br>
	 * dao.createQuery(hql,arg0);<br>
	 * dao.createQuery(hql,arg0,arg1); <br>
	 * dao.createQuery(hql,new Object[arg0,arg1,arg2])<br>
	 * 
	 * @param values
	 *            可变参数.
	 */
	public Query createQuery(String hql, Object... values) {

		Query query = getSession().createQuery(hql);

		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query;
	}

	/**
	 * 根据sql加载分页，默认页大小，从第0条开始
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-25
	 * @param sql
	 * @param values
	 * @return PaginationSupport
	 */
	public PaginationSupport findPageByQuerySQL(String sql, Object... values) {
		return findPageByQuerySQL(sql, 0, PaginationSupport.PAGESIZE, values);
	}

	/**
	 * 根据sql加载分页，默认页大小，从第startIndex条开始
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-25
	 * @param sql
	 * @param startIndex
	 * @param values
	 * @return PaginationSupport
	 */
	public PaginationSupport findPageByQuerySQL(String sql, int startIndex, Object... values) {
		return findPageByQuerySQL(sql, startIndex, PaginationSupport.PAGESIZE, values);
	}

	/**
	 * 根据hql加载分页，指定页大小和起始位置
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-25
	 * @param sql
	 * @param pageSize
	 * @param startIndex
	 * @param values
	 * @return PaginationSupport
	 */
	@SuppressWarnings("unchecked")
	public PaginationSupport findPageByQuerySQL(String sql, int startIndex, int pageSize, Object... values) {
		int totalCount = getCountByQuerySQL(sql, values);

		if (totalCount < 1)
			return new PaginationSupport(new ArrayList(0), 0);

		Query query = createSQLQuery(sql, values);
		List items = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
		PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);
		return ps;
	}

	/**
	 * 得到总的记录数
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-26
	 * @param sql
	 * @param values
	 * @return int
	 */
	public int getCountByQuerySQL(String sql, Object... values) {
		int fromPos = sql.toLowerCase().indexOf("from");
		int distinctPos = sql.toLowerCase().indexOf("distinct");
		if (distinctPos == -1) {
			sql = "select count(*) as cnt " + sql.substring(fromPos);
			List<Object> tempList = new ArrayList<Object>();
			// 去除map元素
			for (int i = 0; i < values.length; i++) {
				if (!(values[i] instanceof Map)) {
					tempList.add(values[i]);
				}
			}
			Query query = createSQLQuery(sql, tempList.toArray());
			return (Integer) query.list().get(0);
		} else {// select 𧧅语句中带有distinct关键字时，无法重新拼凑，直接用原语句取总记录数
			Query query = createSQLQuery(sql, values);
			return query.list().size();
		}

	}

	/**
	 * 执行SQL查询语句<br>
	 * 当参数为map,且map元素的value为Class时，查看结果返回实体对象
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-26
	 * @param sql
	 * @param values
	 * @return Query
	 */
	@SuppressWarnings("unchecked")
	public Query createSQLQuery(String sql, Object... values) {

		SQLQuery query = getSession().createSQLQuery(sql);
		for (int i = 0; i < values.length; i++) {
			if (values[i] instanceof Map) {
				Map map = (Map) values[i];
				Set set = map.entrySet();
				Iterator iterator = set.iterator();
				while (iterator.hasNext()) {
					Map.Entry mapentry = (Map.Entry) iterator.next();
					query.addEntity((String) mapentry.getKey(), (Class) mapentry.getValue());
				}
			} else {
				query.setParameter(i, values[i]);
			}

		}
		return query;
	}

	/**
	 * 执行SQL语句
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com Aug 5, 2010
	 * @param sql
	 * @return
	 */
	public int excuteSql(String sql, Object... values) {
		SQLQuery query = getSession().createSQLQuery(sql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.executeUpdate();
	}

	public void initialize(Object proxy) {
		this.getHibernateTemplate().initialize(proxy);
	}

	public void refresh(T entity) {
		this.getHibernateTemplate().refresh(entity);
	}

	public void flush() {
		this.getHibernateTemplate().flush();
		this.getHibernateTemplate().clear();
	}

	public Long getKey() {
		Long thisKey = EntityKeyUtil.getInstance().getKey(entityClass.getSimpleName());
		if (thisKey == null) {
			putTalbeKeys();
			thisKey = EntityKeyUtil.getInstance().getKey(entityClass.getSimpleName());
			if (thisKey == null) {
				return 1L;
			}
		}
		return thisKey;
	}

	public void setNextKey(Long nextKey) {
		EntityKeyUtil.getInstance().setNextKey(entityClass.getSimpleName(), nextKey);
		Object entityKey = getHibernateTemplate().get(EntityKeySequences.class, entityClass.getSimpleName());
		if (entityKey != null) {
			((EntityKeySequences) entityKey).setNextKey(nextKey);
			this.getHibernateTemplate().update(entityKey);
		} else {
			EntityKeySequences newEntityKey = new EntityKeySequences();
			newEntityKey.setEntityName(entityClass.getSimpleName());
			newEntityKey.setNextKey(nextKey);
			this.getHibernateTemplate().save(newEntityKey);
		}

	}

	@SuppressWarnings("unchecked")
	public void putTalbeKeys() {
		String hql = "from EntityKeySequences";
		List<EntityKeySequences> entityKeys = this.getHibernateTemplate().find(hql);
		EntityKeyUtil.getInstance().putEntityKeys(entityKeys);
	}
}
